package com.clei.utils;

import com.clei.enums.DateConvertTypeEnum;
import com.clei.utils.container.Pair;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;

/**
 * java8 日期时间格式化
 */
public class DateUtil {

    public static final String PATTERN_DATE = "yyyy-MM-dd";

    public static final String PATTERN_DATETIME = "yyyy-MM-dd HH:mm:ss";

    public static final String PATTERN_DATETIME_MS = "yyyy-MM-dd HH:mm:ss.SSS";

    public static final String PATTERN_DATETIME_MS_NUMERIC = "yyyyMMddHHmmssSSS";

    /**
     * TemporalQuery 日期时间类型
     */
    private static final TemporalQuery<LocalDateTime> QUERY_DATETIME = LocalDateTime::from;

    /**
     * TemporalQuery 日期类型
     */
    private static final TemporalQuery<LocalDate> QUERY_DATE = LocalDate::from;

    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_DATE);

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_DATETIME);

    private static final DateTimeFormatter DATE_TIME_MS_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_DATETIME_MS);

    private static final ConcurrentHashMap<String, DateTimeFormatter> FORMATTER_MAP = new ConcurrentHashMap<>(4);

    private static final ZoneId ZONE_ID = ZoneId.systemDefault();

    /**
     * 一秒钟毫秒数
     */
    private static final long SECOND_MILLIS = 1000L;

    /**
     * 一分钟毫秒数
     */
    private static final long MINUTE_MILLIS = SECOND_MILLIS * 60;

    /**
     * 一小时毫秒数
     */
    private static final long HOUR_MILLIS = MINUTE_MILLIS * 60;

    /**
     * 一天毫秒数
     */
    private static final long DAY_MILLIS = HOUR_MILLIS * 24;

    private static final String CONVERTER_KEY_SEPARATOR = "_";

    static {
        // FORMATTER_MAP init
        FORMATTER_MAP.put(PATTERN_DATE, DATE_FORMATTER);
        FORMATTER_MAP.put(PATTERN_DATETIME, DATE_TIME_FORMATTER);
        FORMATTER_MAP.put(PATTERN_DATETIME_MS, DATE_TIME_MS_FORMATTER);
    }

    public static String getDefaultPattern() {
        return PATTERN_DATETIME;
    }

    /**
     * 返回默认格式的 当前日期字符串
     *
     * @return String
     */
    public static String currentDate() {
        return currentDate(PATTERN_DATE);
    }

    /**
     * 返回指定格式的格式的 当前日期字符串
     *
     * @param pattern 指定日期格式
     * @return String
     */
    public static String currentDate(String pattern) {
        return format(LocalDate.now(), pattern);
    }

    /**
     * 返回默认格式的 当前日期时间字符串
     *
     * @return
     */
    public static String currentDateTime() {
        return currentDateTime(PATTERN_DATETIME);
    }

    /**
     * 返回默认格式的 当前日期时间字符串
     *
     * @return
     */
    public static String currentDateTimeNumeric() {
        return currentDateTime(PATTERN_DATETIME_MS_NUMERIC);
    }

    /**
     * 返回指定格式的格式的 当前日期时间字符串
     *
     * @param ms 是否打印毫秒
     * @return
     */
    public static String currentDateTime(boolean ms) {
        return currentDateTime(ms ? PATTERN_DATETIME_MS : PATTERN_DATETIME);
    }

    /**
     * 返回指定格式的格式的 当前日期时间字符串
     *
     * @param pattern 指定日期格式
     * @return
     */
    public static String currentDateTime(String pattern) {
        return format(LocalDateTime.now(), pattern);
    }

    /**
     * 根据epochMilli返回格式化日期字符串
     *
     * @param millis
     * @return
     */
    public static String formatMillis(long millis) {
        return format(fromMillis(millis));
    }

    /**
     * 根据epochMilli返回格式化日期字符串
     *
     * @param millis
     * @param pattern 指定格式化样例
     * @return
     */
    public static String formatMillis(long millis, String pattern) {
        return format(fromMillis(millis), pattern);
    }

    /**
     * 根据epochMilli返回格式化日期字符串
     *
     * @param millis
     * @param dateTimeFormatter 指定格式化器
     * @return
     */
    public static String formatMillis(long millis, DateTimeFormatter dateTimeFormatter) {
        return format(fromMillis(millis), dateTimeFormatter);
    }

    /**
     * format
     *
     * @param obj Object
     * @return String
     */
    public static String format(Object obj) {
        return format(convert(obj, LocalDateTime.class));
    }

    /**
     * 使用TemporalAccessor增加扩展性
     *
     * @param temporal
     * @return
     */
    public static String format(TemporalAccessor temporal) {
        return format(temporal, DATE_TIME_FORMATTER);
    }

    public static String format(TemporalAccessor temporal, String pattern) {
        DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(pattern);
        return format(temporal, dateTimeFormatter);
    }

    /**
     * format
     *
     * @param date Date
     * @return String
     */
    public static String format(Date date) {
        LocalDateTime localDateTime = toLocalDateTime(date);
        return format(localDateTime);
    }

    /**
     * format
     *
     * @param date    Date
     * @param pattern pattern
     * @return String
     */
    public static String format(Date date, String pattern) {
        DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(pattern);
        LocalDateTime localDateTime = toLocalDateTime(date);
        return format(localDateTime, dateTimeFormatter);
    }

    /**
     * formatDate
     *
     * @param temporal TemporalAccessor
     * @return String
     */
    public static String formatDate(TemporalAccessor temporal) {
        return format(temporal, DATE_FORMATTER);
    }

    /**
     * formatDate
     *
     * @param date Date
     * @return String
     */
    public static String formatDate(Date date) {
        LocalDateTime localDateTime = toLocalDateTime(date);
        return formatDate(localDateTime);
    }

    /**
     * formatIso8601
     * ZonedDateTime -> String
     *
     * @param zonedDateTime ZonedDateTime
     * @return String
     */
    public static String formatIso8601(ZonedDateTime zonedDateTime) {
        return zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
    }

    /**
     * 昨日之始
     *
     * @return
     */
    public static LocalDateTime yesterdayBegin() {
        return todayBegin().plusDays(-1);
    }

    /**
     * 今日之始
     *
     * @return 今日之始
     */
    public static LocalDateTime todayBegin() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
    }

    /**
     * 今日之始
     *
     * @param clazz 返回类型class
     * @param <T>   返回目标类型
     * @return 今日之始
     */
    public static <T> T todayBegin(Class<T> clazz) {
        return convert(todayBegin(), clazz);
    }

    /**
     * 明日之始
     *
     * @return 明日之始
     */
    public static LocalDateTime tomorrowBegin() {
        return todayBegin().plusDays(1);
    }

    /**
     * 明日之始
     *
     * @param clazz 返回类型class
     * @param <T>   返回目标类型
     * @return 明日之始
     */
    public static <T> T tomorrowBegin(Class<T> clazz) {
        return convert(tomorrowBegin(), clazz);
    }

    /**
     * 根据epochMilli获取 LocalDateTime
     *
     * @param millis
     * @return
     */
    public static LocalDateTime fromMillis(long millis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZONE_ID);
    }

    /**
     * 根据epochSecond获取 LocalDateTime
     *
     * @param seconds
     * @return
     */
    public static LocalDateTime fromSeconds(long seconds) {
        return LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds), ZONE_ID);
    }

    public static LocalDateTime parse(String date) {
        return parse(date, QUERY_DATETIME);
    }

    public static <T> T parse(String date, TemporalQuery<T> query) {
        return parse(date, DATE_TIME_FORMATTER, query);
    }

    public static LocalDateTime parse(String date, String pattern) {
        return parse(date, pattern, QUERY_DATETIME);
    }

    /**
     * String -> LocalDate
     *
     * @param date String
     * @return LocalDate
     */
    public static LocalDate parseDate(String date) {
        return parse(date, DATE_FORMATTER, QUERY_DATE);
    }

    /**
     * String -> LocalDate
     *
     * @param pattern 日期格式
     * @param date    String
     * @return LocalDate
     */
    public static LocalDate parseDate(String date, String pattern) {
        return parse(date, pattern, QUERY_DATE);
    }

    /**
     * parseIso8601
     * String -> ZonedDateTime
     *
     * @param str String
     * @return ZonedDateTime
     */
    public static ZonedDateTime parseIso8601(String str) {
        return ZonedDateTime.parse(str, DateTimeFormatter.ISO_ZONED_DATE_TIME);
    }

    public static <T> T parse(String date, String pattern, TemporalQuery<T> query) {
        DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(pattern);
        return parse(date, dateTimeFormatter, query);
    }

    public static Instant toInstant(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZONE_ID).toInstant();
    }

    public static long toEpochMilli(LocalDateTime localDateTime) {
        return toInstant(localDateTime).toEpochMilli();
    }

    /**
     * String date -> epochMilli
     *
     * @param date String
     * @return epochMilli
     */
    public static long toEpochMilli(String date) {
        return toEpochMilli(parse(date));
    }

    /**
     * LocalDateTime -> epochSecond
     *
     * @param localDateTime LocalDateTime
     * @return epochSecond
     */
    public static long toEpochSecond(LocalDateTime localDateTime) {
        return toInstant(localDateTime).getEpochSecond();
    }

    /**
     * String -> epochSecond
     *
     * @param date String
     * @return epochSecond
     */
    public static long toEpochSecond(String date) {
        return toEpochSecond(parse(date));
    }

    /**
     * LocalDateTime -> Date
     *
     * @param localDateTime LocalDateTime
     * @return Date
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(toInstant(localDateTime));
    }

    /**
     * LocalDate -> Date
     *
     * @param localDate LocalDate
     * @return Date
     */
    public static Date toDate(LocalDate localDate) {
        return toDate(LocalDateTime.of(localDate, LocalTime.MIN));
    }

    /**
     * String -> Date
     *
     * @param date String
     * @return Date
     */
    public static Date toDate(String date) {
        return toDate(parse(date));
    }

    /**
     * String -> Date
     *
     * @param date    String
     * @param pattern date格式
     * @return Date
     */
    public static Date toDate(String date, String pattern) {
        return toDate(parse(date, pattern));
    }

    /**
     * Date -> LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(String date) {
        return LocalDateTime.parse(date, DATE_TIME_FORMATTER);
    }

    /**
     * Date -> LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZONE_ID);
    }

    /**
     * 类型转换
     *
     * @param t      被转换的对象
     * @param rClass 返回对象class
     * @param <T>    转换参数类型
     * @param <R>    转换目标类型
     * @return r
     */
    @SuppressWarnings("unchecked")
    public static <T, R> R convert(T t, Class<R> rClass) {
        if (null == t || null == rClass) {
            return null;
        }
        if (t.getClass() == rClass) {
            return (R) t;
        }
        String key = t.getClass().getSimpleName() + CONVERTER_KEY_SEPARATOR + rClass.getSimpleName();
        DateConvertTypeEnum convertType = DateConvertTypeEnum.getByName(key.toUpperCase());
        if (null == convertType) {
            return null;
        }
        Object r = null;
        switch (convertType) {
            case STRING_LONG:
                r = toEpochMilli(t.toString());
                break;
            case STRING_LOCALDATETIME:
                r = parse(t.toString());
                break;
            case STRING_LOCALDATE:
                r = parseDate(t.toString());
                break;
            case STRING_DATE:
                r = toDate(t.toString());
                break;
            case LONG_STRING:
                r = formatMillis((Long) t);
                break;
            case LONG_LOCALDATETIME:
                r = fromMillis((Long) t);
                break;
            case LONG_LOCALDATE:
                r = fromMillis((Long) t).toLocalDate();
                break;
            case LONG_DATE:
                r = new Date((Long) t);
                break;
            case LOCALDATETIME_STRING:
                r = format((LocalDateTime) t);
                break;
            case LOCALDATETIME_LONG:
                r = toEpochMilli((LocalDateTime) t);
                break;
            case LOCALDATETIME_LOCALDATE:
                r = ((LocalDateTime) t).toLocalDate();
                break;
            case LOCALDATETIME_DATE:
                r = toDate((LocalDateTime) t);
                break;
            case LOCALDATE_STRING:
                r = formatDate((LocalDate) t);
                break;
            case LOCALDATE_LONG:
                r = toEpochMilli(LocalDateTime.of((LocalDate) t, LocalTime.MIN));
                break;
            case LOCALDATE_LOCALDATETIME:
                r = LocalDateTime.of((LocalDate) t, LocalTime.MIN);
                break;
            case LOCALDATE_DATE:
                r = toDate(LocalDateTime.of((LocalDate) t, LocalTime.MIN));
                break;
            case DATE_STRING:
                r = format((Date) t);
                break;
            case DATE_LONG:
                r = ((Date) t).getTime();
                break;
            case DATE_LOCALDATETIME:
                r = toLocalDateTime((Date) t);
                break;
            case DATE_LOCALDATE:
                r = toLocalDateTime((Date) t).toLocalDate();
                break;
            default:
        }
        return (R) r;
    }

    /**
     * 两个日期的时间差 3天2小时1分钟这样子
     *
     * @param start 开始时间
     * @param end   结束时间
     * @return 时段长度
     */
    public static String getDuration(LocalDateTime start, LocalDateTime end) {
        return getDuration(ChronoUnit.MILLIS.between(start, end));
    }

    /**
     * 两个日期的时间差 3天2小时1分这样子
     *
     * @param start
     * @param end
     * @return
     */
    public static String getDuration(Date start, Date end) {
        return getDuration(start.getTime(), end.getTime());
    }

    /**
     * 两个日期的时间差 3天2小时1分这样子
     *
     * @param start
     * @param end
     * @return
     */
    public static String getDuration(long start, long end) {
        return getDuration(end - start);
    }

    /**
     * 判断两个日期是否是同一天
     *
     * @param temporal1
     * @param temporal2
     * @return
     */
    public static boolean isSameDay(TemporalAccessor temporal1, TemporalAccessor temporal2) {
        return temporal1.get(ChronoField.YEAR) == temporal2.get(ChronoField.YEAR)
                && temporal1.get(ChronoField.DAY_OF_YEAR) == temporal2.get(ChronoField.DAY_OF_YEAR);
    }

    /**
     * 分割成多个时间段
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param days      时间段长度 天
     * @return 多个时间段
     */
    public static List<Pair<LocalDateTime, LocalDateTime>> cutByDays(LocalDateTime startDate, LocalDateTime endDate, int days) {
        return cutByRange(startDate, endDate, (long) days * 60 * 60 * 24);
    }

    /**
     * 分割成多个时间段
     *
     * @param startDate       开始日期
     * @param endDate         结束日期
     * @param timeRangeLength 时间段长度 单位秒
     * @return 多个时间段
     */
    public static List<Pair<LocalDateTime, LocalDateTime>> cutByRange(LocalDateTime startDate, LocalDateTime endDate, long timeRangeLength) {
        long diff = ChronoUnit.SECONDS.between(startDate, endDate);
        if (diff <= 0) {
            throw new RuntimeException("开始日期必须小于结束日期");
        }
        int length = (int) (0 == diff % timeRangeLength ? diff / timeRangeLength : diff / timeRangeLength + 1);
        List<Pair<LocalDateTime, LocalDateTime>> result = new ArrayList<>(length);
        // 必须before 不能有=的状况，不然会死循环
        while (startDate.isBefore(endDate)) {
            LocalDateTime tempEnd = startDate.plusSeconds(timeRangeLength);
            // tempEnd 和 tempEnd取小的那个
            if (tempEnd.isAfter(endDate)) {
                tempEnd = endDate;
            }
            result.add(Pair.of(startDate, tempEnd));
            startDate = tempEnd;
        }
        return result;
    }

    /**
     * dateList
     *
     * @param dateType  年/月/日 YEAR/MONTH/DAY
     * @param startDate 开始日期 yyyy-MM-dd
     * @param endDate   结束日期 yyyy-MM-dd
     * @return dateList
     */
    public static List<String> dateList(String dateType, String startDate, String endDate) {
        LocalDateTime start = null, end = null;
        BiFunction<LocalDateTime, Long, LocalDateTime> stepFunc = null;
        int size = 0;
        int subEndIndex = -1;
        switch (dateType) {
            case "YEAR":
                start = toLocalDateTime(startDate.substring(0, 7) + "-01 00:00:00");
                end = toLocalDateTime(endDate.substring(0, 7) + "-01 00:00:00");
                stepFunc = LocalDateTime::plusMonths;
                size = (int) ChronoUnit.MONTHS.between(start, end);
                subEndIndex = 7;
                break;
            case "MONTH":
                start = toLocalDateTime(startDate + " 00:00:00");
                end = toLocalDateTime(endDate + " 00:00:00");
                stepFunc = LocalDateTime::plusDays;
                size = (int) ChronoUnit.DAYS.between(start, end);
                subEndIndex = 10;
                break;
            case "DAY":
                start = toLocalDateTime(startDate + " 00:00:00");
                end = toLocalDateTime(endDate + " 23:00:00");
                stepFunc = LocalDateTime::plusHours;
                size = (int) ChronoUnit.HOURS.between(start, end);
                break;
            default:
                return Collections.emptyList();
        }

        List<String> resList = new ArrayList<>(size + 1);
        while (!start.isAfter(end)) {
            String dateStr = format(start);
            start = stepFunc.apply(start, 1L);
            if (-1 != subEndIndex) {
                dateStr = dateStr.substring(0, subEndIndex);
            }
            resList.add(dateStr);
        }
        return resList;
    }

    /**
     * dateRange
     *
     * @param dateType  年/月/日 YEAR/MONTH/DAY
     * @param startDate 开始日期 年yyyy 月yyyy-MM 日yyyy-MM-dd
     * @param endDate   结束日期 年yyyy 月yyyy-MM 日yyyy-MM-dd
     * @return dateRange
     */
    public static Pair<String, String> dateRange(String dateType, String startDate, String endDate) {
        switch (dateType) {
            case "YEAR":
                startDate = startDate + "-01-01 00:00:00";
                endDate = endDate + "-12-31 23:59:59";
                break;
            case "MONTH":
                startDate = startDate + "-01 00:00:00";
                endDate = endDate + "-01 00:00:00";
                LocalDateTime endDateTime = toLocalDateTime(endDate);
                endDate = format(endDateTime.plusMonths(1L).minusNanos(1L));
                break;
            case "DAY":
                startDate = startDate + " 00:00:00";
                endDate = endDate + " 23:59:59";
                break;
            default:
                throw new RuntimeException("未知日期类型");
        }
        return Pair.of(startDate, endDate);
    }

    /**
     * dateList
     *
     * @param dateType  年/月/日 YEAR/MONTH/DAY
     * @param startDate 开始日期 yyyy-MM-dd
     * @param endDate   结束日期 yyyy-MM-dd
     * @return dateList
     */
    public static List<Pair<String, String>> dateRangeList(String dateType, String startDate, String endDate) {
        LocalDateTime start, end;
        BiFunction<LocalDateTime, Long, LocalDateTime> stepFunc = null;
        int size;
        start = toLocalDateTime(startDate + " 00:00:00");
        end = toLocalDateTime(endDate + " 23:59:59");
        switch (dateType) {
            case "YEAR":
                stepFunc = LocalDateTime::plusMonths;
                size = (int) ChronoUnit.MONTHS.between(start, end);
                break;
            case "MONTH":
                stepFunc = LocalDateTime::plusDays;
                size = (int) ChronoUnit.DAYS.between(start, end);
                break;
            case "DAY":
                stepFunc = LocalDateTime::plusHours;
                size = (int) ChronoUnit.HOURS.between(start, end);
                break;
            default:
                return Collections.emptyList();
        }

        List<Pair<String, String>> resList = new ArrayList<>(size + 1);
        String first = format(start);
        while (start.isBefore(end)) {
            start = stepFunc.apply(start, 1L);
            if (start.isAfter(end)) {
                start = end;
            }
            String second = format(start);
            resList.add(Pair.of(first, second));
            first = second;
        }
        return resList;
    }

    /**
     * getPrevDateRange
     *
     * @param dateType  年YEAR 月MONTH
     * @param dateRange 年yyyy 月yyyy-MM 日yyyy-MM-dd
     * @return Pair
     */
    public static Pair<String, String> getPrevDateRange(String dateType, Pair<String, String> dateRange) {
        LocalDate start = null, end = null;
        int interval = 0;
        String startDate = dateRange.getFirst();
        String endDate = dateRange.getSecond();

        switch (dateType) {
            case "YEAR":
                int startInt = Integer.parseInt(startDate);
                int endInt = Integer.parseInt(endDate);
                interval = endInt - startInt + 1;
                startDate = String.valueOf(startInt - interval);
                endDate = String.valueOf(endInt - interval);
                break;
            case "MONTH":
                startDate = startDate + "-01";
                endDate = endDate + "-01";
                start = parseDate(startDate);
                end = parseDate(endDate);
                interval = (int) ChronoUnit.MONTHS.between(start, end) + 1;
                startDate = formatDate(start.minusMonths(interval)).substring(0, 7);
                endDate = formatDate(end.minusMonths(interval)).substring(0, 7);
                break;
            case "DAY":
                start = parseDate(startDate);
                end = parseDate(endDate);
                interval = (int) ChronoUnit.DAYS.between(start, end) + 1;
                startDate = formatDate(start.minusDays(interval));
                endDate = formatDate(end.minusDays(interval));
                break;
            default:
                throw new RuntimeException("未知日期类型");
        }
        return Pair.of(startDate, endDate);
    }

    /**
     * 两个日期的时间差 3天2小时1分钟这样子
     *
     * @param millis 毫秒数
     * @return 时段长度
     */
    private static String getDuration(long millis) {
        if (0 > millis) {
            throw new RuntimeException("时间错误！");
        }
        if (MINUTE_MILLIS > millis) {
            return millis > 0 ? "1分钟" : "0分钟";
        }
        StringBuilder sb = new StringBuilder();
        long dayDiff = millis / DAY_MILLIS;
        if (0 < dayDiff) {
            sb.append(dayDiff);
            sb.append("天");
        }
        millis = millis % DAY_MILLIS;
        long hourDiff = millis / HOUR_MILLIS;
        if (0 < hourDiff) {
            sb.append(hourDiff);
            sb.append("小时");
        }
        millis = millis % HOUR_MILLIS;
        millis = millis + MINUTE_MILLIS - 1;
        long minuteDiff = millis / MINUTE_MILLIS;
        if (0 < minuteDiff) {
            sb.append(minuteDiff);
            sb.append("分钟");
        }
        return sb.toString();
    }

    private static String format(TemporalAccessor temporal, DateTimeFormatter dateTimeFormatter) {
        return dateTimeFormatter.format(temporal);
    }

    private static <T> T parse(String date, DateTimeFormatter dateTimeFormatter, TemporalQuery<T> query) {
        return dateTimeFormatter.parse(date, query);
    }

    /**
     * 根据pattern获取DateTimeFormatter
     *
     * @param pattern
     * @return
     */
    private static DateTimeFormatter getDateTimeFormatter(String pattern) {
        DateTimeFormatter dateTimeFormatter = FORMATTER_MAP.get(pattern);
        if (null == dateTimeFormatter) {
            dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
            //放入格式化器map里
            FORMATTER_MAP.put(pattern, dateTimeFormatter);
        }
        return dateTimeFormatter;
    }
}